const defAttr = () => ({
    data: {},//drawArrays
    // 'a_Position': {
    //     size: 2, 必须
    //     array: [], 必须
    //     buffer: null,
    //     location: a_Position,
    //     needUpdate: true //是否需要更新
    // }
    element: null,//drawElements
    //{
    //     array:[], 必须
    //     buffer: null,
    //     needUpdate: true //是否需要更新
    //}
    count: 0,//顶点数量 用于渲染是使用
    drawType: 'drawArrays'//渲染方法
})


//集合体对象
//只存储Attrib类型的对象
export default class Geo {
    constructor(attr) {
        Object.assign(this, defAttr(), attr);
    }

    init(gl) {
        this._initData(gl);
        this._initIndex(gl);
        this._updateDrawCount();
    }

    //初始化顶点信息
    _initData(gl) {
        Object.entries(this.data).forEach(([key, value], index) => {
            let buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, value.array, gl.STATIC_DRAW);
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            value.buffer = buffer;
            value.needUpdate = true;
        });
    }

    //初始化顶点索引
    _initIndex(gl) {
        const { element } = this;
        if (element) {
            let buffer = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, element.array, gl.STATIC_DRAW);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
            element.buffer = buffer;
            element.needUpdate = true;
        }
    }

    _updateDrawCount() {
        const { element } = this;
        if (element) {
            this.count = element.array.length;
            this.drawType = 'drawElements';
        } else {
            const { array, size } = this.data['a_Position'];
            this.count = array.length / size;
            this.drawType = 'drawArrays';
        }
    }

    update(gl, attribs) {
        this._updateData(gl, attribs);
        this._updataIndex(gl);
    }

    //attribs是Map对象
    _updateData(gl, attribs) {
        Object.entries(this.data).forEach(([key, value], index) => {
            const { size, buffer, array } = value;
            const location = attribs.get(key);
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            if (value.needUpdate) {
                gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
                gl.vertexAttribPointer(location, value.size, gl.FLOAT, false, 0, 0);//因为只传入顶点数据点数据,所以后两位可以直接填0
                gl.enableVertexAttribArray(location);
                value.needUpdate = false;

                if (key == 'a_Position') {
                    this._updateDrawCount();
                }
            }
            gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
        });
    }

    _updataIndex(gl) {
        const { element } = this;
        if (element) {
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, element.buffer);
            if (element.needUpdate) {
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, element.array, gl.STATIC_DRAW)
                element.needUpdate = false;
            }
        }
    }

    setData(key, value) {
        const { data } = this;
        if (!data[key]) {
            console.log('data null');
            return;
        }
        data[key].needUpdate = true;
        Object.assign(data[key], value);
    }

    setElement(value) {
        if (value) {
            if (this.element == null) {
                this.element = {};
            }
            const { element } = this;
            this.count = value.length;
            element.array = value;
            element.needUpdate = true;
            this.drawType = 'drawElements';
        } else {
            const { array, size } = this.data['a_Position'];
            this.count = array.length / size;
            this.drawType = 'drawArrays';
        }
    }

    clone() {
        const { data, element } = this;

        let curData = {};
        Object.entries(data).forEach(([key, val], index) => {
            curData[key] = {
                size: val.size,
                array: new Float32Array(val.array),
            };
        })

        let curElement = {
            array: new Uint8Array(element.array),
        };

        return new Geo({
            data: curData,
            element: curElement,
        });
    }

}